import {
  BadRequestException,
  HttpException,
  HttpStatus,
  Injectable,
  Logger,
} from '@nestjs/common';
import { CreateUserDto } from './dto/create-user.dto';
import { UpdateUserDto } from './dto/update-user.dto';
import { PrismaService } from 'nestjs-prisma';
import { NumberToBool } from '../../common/utils/util';
import { decode, encryption } from '../../common/utils/crypto';
import { QueryPageDto } from '../../common/dto/query.page.dto';
import { QueryUserDto } from './dto/query-user.dto';
import { PageDto } from '../../common/dto/page.dto';
import { Prisma } from '@prisma/client';
import { GetSkit, GetSort } from '../../common/utils/query';
import { ResetUserDto } from './dto/reset-user.dto';
import { UpdateUserInfoDto } from './dto/update-user-info.dto';
import { ResetUserPasswordDto } from './dto/reset-user-password.dto';
import { Role } from '../../common/types/role';

@Injectable()
export class UserService {
  logger = new Logger(UserService.name);
  constructor(private prisma: PrismaService) {
    this.initDefaultData().then(() => {
      this.logger.log('初始化完成！');
    });
  }

  async initDefaultData() {
    const admin = await this.prisma.user.findUnique({
      where: {
        username: 'admin',
      },
    });

    const roles = await this.prisma.role.count();
    if (roles == 0) {
      await this.prisma.role.createMany({
        data: Object.keys(Role).map((name) => {
          return {
            name: name,
          };
        }),
      });
    }
    if (!admin) {
      const { password, iv, key } = encryption('admin123!~');
      await this.prisma.user.create({
        data: {
          username: 'admin',
          password: password,
          iv: iv,
          key: key,
          role: {
            connect: {
              name: 'ADMIN',
            },
          },
        },
      });
    }

    // if (!admin) {
    //   await this.prisma.user.create({
    //     data: {},
    //   });
    // }
  }

  async create(createUserDto: CreateUserDto) {
    const { password, iv, key } = encryption(createUserDto.password);
    return await this.prisma.user.create({
      data: {
        ...createUserDto,
        password,
        iv,
        key,
      },
    });
  }

  async findByPage(query: QueryPageDto<QueryUserDto>) {
    const result = new PageDto(query);
    const where: Prisma.UserWhereInput = {
      username: {
        contains: query.model?.username || undefined,
      },
      disabled: NumberToBool(query.model?.disabled),
      mobile: {
        contains: query.model?.mobile || undefined,
      },
    };
    const skip = GetSkit(query);
    const order = GetSort(query);
    const record = this.prisma.user.findMany({
      where: where,
      ...skip,
      ...order,
      include: {
        role: {
          select: {
            title: true,
            name: true,
          },
        },
      },
    });

    const total = this.prisma.user.count({ where });

    const users = await this.prisma.$transaction([record, total]).catch((e) => {
      this.logger.error(e.message);
      throw new HttpException(e.message, HttpStatus.BAD_REQUEST);
    });
    result.record = users[0].map((item: any) => {
      delete item.password;
      delete item.iv;
      delete item.key;
      return item;
    });
    result.total = users[1];

    return result;
  }

  async findOne(id: string) {
    const result: any = await this.prisma.user.findUnique({
      where: {
        id,
      },
      include: {
        role: {
          select: {
            id: true,
            name: true,
          },
        },
      },
    });
    delete result.password;
    delete result.iv;
    delete result.key;
    return result;
  }

  update(id: string, updateUserDto: UpdateUserDto) {
    return this.prisma.user.update({
      where: {
        id,
      },
      data: {
        ...updateUserDto,
      },
    });
  }

  async remove(id: string) {
    const delUser = this.prisma.user.delete({
      where: {
        id,
      },
    });

    await this.prisma.$transaction([delUser]);

    return 'ok';
  }

  resetPassword(id: string, form: ResetUserDto) {
    const { iv, password, key } = encryption(form.password);
    return this.prisma.user.update({
      where: { id },
      data: {
        iv,
        password,
        key,
      },
    });
  }

  async newPassword(id: string, form: ResetUserPasswordDto) {
    const { iv, password, key } = encryption(form.newPassword);
    const user = await this.prisma.user.findUniqueOrThrow({
      where: {
        id,
      },
    });
    const oldPassword = decode(user.password, user.key, user.iv);
    if (oldPassword != form.password) {
      throw new BadRequestException('旧密码错误！');
    }
    return this.prisma.user.update({
      where: { id },
      data: {
        iv,
        password,
        key,
      },
    });
  }

  async updateUserInfo(userId: string, userInfo: UpdateUserInfoDto) {
    await this.prisma.user.update({
      where: {
        id: userId,
      },
      data: userInfo,
    });
  }

  findAll() {
    return this.prisma.user.findMany({
      where: {
        disabled: false,
      },
      select: {
        id: true,
        username: true,
      },
    });
  }

  async getProfile(id: string) {
    return this.prisma.user.findUnique({
      where: {
        id,
      },
      select: {
        id: true,
        username: true,
        remark: true,
        mobile: true,
        role: true,
        createdAt: true,
        updatedAt: true,
      },
    });
  }
}
